#pragma once

#ifndef _DROPLET_RENDERER
#define _DROPLET_RENDERER

#include <OGLGlobals.h>
#include <OGLRenderer.h>
#include <OGLViewControl.h>
#include <OGLWindowControl.h>

#include <btBulletCollisionCommon.h>
#include <IDroplet.h>
#include <IDropletSim.h>
#include <DropletRainbow/DropletRainbow.h>
#include <DropletDataStructs.h>

#include "RenderableObject.h"
#include "RenderableDroplet.h"

#include <gl/glew.h>
#include <gl/GLU.h>
#include <gl/glfw.h>

#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <vector>
#include <utility>

#define VERTEX_SHADER_FILE		"SimpleVertexShader.glsl"
#define FRAGMENT_SHADER_FILE	"SimpleFragmentShader.glsl"
#define DROPLET_MODEL_FILE		"SimpleDroplet.txt"
#define FLOOR_MODEL_FILE		"SimpleFloor.txt"
#define WALLX_MODEL_FILE		"SimpleWallX.txt"
#define WALLY_MODEL_FILE		"SimpleWallY.txt"

// Droplet Simulator specific constants
#define DEFAULT_ROW_TILES 4
#define DEFAULT_COL_TILES 4
#define DEFAULT_NUM_DROPLETS 4
#define DEFAULT_TILE_LENGTH 24.0f
#define DEFAULT_DROPLET_RADIUS 2.0f
#define DEFAULT_WALL_HEIGHT 5.0f // in cm
#define DEFAULT_WALL_WIDTH	5.0f
#define DEFAULT_FPS 60.0f	// 60 frames per second

class DropletRenderer : public OGLRenderer
{
private :

	enum RenderableObjectType
	{
		DEFAULT,
		DROPLET
	};

	// Renderer specific values
	std::vector<RenderableObject *> renderableObjects;
	GLuint vaoID, programID, vertexShaderID, fragmentShaderID;
	int objectCounter;	
	bool firstUpdate;
	
	// Simulator specific values
	IDropletSim sim;
	int btXWallShapeID, btYWallShapeID, btFloorShapeID, btDropletShapeID;
	int numRowTiles, numColTiles, numDroplets;
	float tileLength, dropletRadius, wallHeight, wallWidth, fps;
	std::vector<unsigned char *> *dropletColors;
	std::vector<float *> *dropletPos;

	// Random number generators
	float getRandomf(float min, float max); 	// Use srand() first to seed!
	float getRandomf(void);

	OGLResult createVAO(void);
	OGLResult loadShader(
		std::string shaderFilepath, 
		GLenum shaderType, 
		GLuint *shaderID
	);
	OGLResult loadProgram(
		std::string vertexShaderFilepath, 
		std::string fragmentShaderFilepath
	);

	// Set up and tear down functions for the renderer
	OGLResult setupWalls(void);
	OGLResult setupFloor(void);
	OGLResult setupDroplets(void);

	RenderableObject *createRenderableObject(
		std::string modelFilepath,
		glm::vec3 startPosition,
		GLenum dataType,
		GLenum usageType,
		GLenum drawType,
		RenderableObjectType objType);

	OGLResult destroyArrayObjects(void);
	OGLResult destroyShadersAndPrograms(void);

	// Simulator set up functions
	void initSimulator(void);
	void setupSimObjects(void);

public :
	
	DropletRenderer(void);
	~DropletRenderer(void);

	OGLResult LoopInitialize(void);
	OGLResult LoopIterate(void);
	OGLResult LoopUpdate(void);
	OGLResult LoopComplete(void);

};

#endif